<template>
    <!-- <h5 class="form-lable">{{title}}</h5> -->
    <div class="form-floating mb-3">
        <input
            v-if="tag !== 'textarea'"
            :class="{ 'is-invalid': inputRef.error, 'is-valid': !inputRef.error && inputRef.val }"
            class="form-control"
            v-model="inputRef.val"
            @blur="validateInput"
            @input="updateValue"
            v-bind="$attrs"
        />
        <textarea
            v-else
            :class="{ 'is-invalid': inputRef.error, 'is-valid': !inputRef.error && inputRef.val }"
            class="form-control"
            v-model="inputRef.val"
            @blur="validateInput"
            @input="updateValue"
            v-bind="$attrs"
        ></textarea>
        <span
            :class="{ 'text-danger': inputRef.error, 'text-success': !inputRef.error && inputRef.val !== '' }"
        >{{ inputRef.message }}</span>
    </div>
</template>

<script lang="ts">
import { onMounted,PropType, reactive, defineComponent, watch } from 'vue';
import { emitter } from './ValidateForm.vue';
import { RulesProp, TagType } from '@/types';

export default defineComponent({
    // 禁止组件属性绑定
    inheritAttrs: false,
    props: {
        rules: {
            type: Array as PropType<RulesProp>,
            required: true
        },
        title: String,
        // 子组件内部实现 v-model 双向数据绑定
        modelValue: String,
        tag: {
            type: String as PropType<TagType>,
            default: 'input'
        }
    },
    setup(props, context) {
        // console.log(context.attrs)
        const emailReg = /^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/;
        const inputRef = reactive({
            val: props.modelValue || '',
            error: false,
            message: props.title || ''
        });

        watch(() => props.modelValue, (newVal) => {
            inputRef.val = newVal || '';
        })
        /**
         * 
         * @param e : KeyboardEvent 会报与 Event 类型不一致
         */
        const updateValue = (e: Event) => {
            const targetValue = (e.target as HTMLInputElement).value;
            inputRef.val = targetValue;
            context.emit('update:modelValue', targetValue);
        }

        /**
         * common
         */
        const validateInput = () => {
            if (props.rules) {
                const allPassed = props.rules.every(rule => {
                    // console.log("modal is =>", props.modelValue);
                    let passed = false;
                    inputRef.message = rule.message;
                    switch (rule.type) {
                        case 'required':
                            passed = (inputRef.val.trim() !== '');
                            break;
                        case 'email':
                            passed = emailReg.test(inputRef.val);
                            break;
                        case 'min':
                            if (rule.length) {
                                passed = inputRef.val.length >= rule.length;
                            }
                            break;
                        case 'max':
                            if (rule.length) {
                                passed = inputRef.val.length <= rule.length;
                            }
                            break;
                        case 'custom': 
                            passed = rule.validator ? rule.validator() : true;
                            break;
                        default:
                            break; 
                    }
                    return passed; 
                });
                // console.log("validation result is =>", allPassed);
                inputRef.error = !allPassed;
                if (allPassed) {
                    inputRef.message = '验证通过';
                }
                return allPassed;
            }
            return true;
            // console.error('error');
        }

        onMounted(() => {
            // 发送外部传递过来的值
            emitter.emit('formItemCreated', validateInput);
        })

        return {
            inputRef,
            updateValue,
            validateInput
        }
    }
});
</script>